package online.foxnull2.foxmall.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import online.foxnull2.foxmall.product.entity.SkuImagesEntity;
import online.foxnull2.foxmall.product.entity.SkuInfoEntity;
import online.foxnull2.foxmall.product.entity.SpuInfoDescEntity;
import online.foxnull2.foxmall.product.feign.SeckillFeignService;
import online.foxnull2.foxmall.product.feign.WareFeignService;
import online.foxnull2.foxmall.product.mapper.SkuInfoMapper;
import online.foxnull2.foxmall.product.service.*;
import online.foxnull2.foxmall.product.utils.PageUtils;
import online.foxnull2.foxmall.product.utils.Query;
import online.foxnull2.foxmall.product.vo.SeckillSkuRedisVo;
import online.foxnull2.foxmall.product.vo.skuItem.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Slf4j
@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfoEntity> implements SkuInfoService {

    private final SkuImagesService skuImagesService;
    private final SpuInfoDescService spuInfoDescService;
    private final AttrGroupService attrGroupService;
    private final SkuSaleAttrValueService skuSaleAttrValueService;
    private final WareFeignService wareFeignService;
    private final ThreadPoolExecutor executor;
    private final SeckillFeignService seckillFeignService;

    @Autowired
    public SkuInfoServiceImpl(SkuImagesService skuImagesService,
                              SpuInfoDescService spuInfoDescService,
                              AttrGroupService attrGroupService,
                              SkuSaleAttrValueService skuSaleAttrValueService,
                              @Qualifier("online.foxnull2.foxmall.product.feign.WareFeignService") WareFeignService wareFeignService,
                              ThreadPoolExecutor executor,
                              @Qualifier("online.foxnull2.foxmall.product.feign.SeckillFeignService") SeckillFeignService seckillFeignService) {
        this.skuImagesService = skuImagesService;
        this.spuInfoDescService = spuInfoDescService;
        this.attrGroupService = attrGroupService;
        this.skuSaleAttrValueService = skuSaleAttrValueService;
        this.wareFeignService = wareFeignService;
        this.executor = executor;
        this.seckillFeignService = seckillFeignService;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();
        Object key = params.get("key");
        if (!ObjectUtils.isEmpty(key)) {
            queryWrapper.and(wrapper -> wrapper.eq("sku_id", key).or().like("sku_name", key));
        }
        Object catelogId = params.get("catelogId");
        if (!ObjectUtils.isEmpty(catelogId)) {
            queryWrapper.eq("catalog_id", catelogId);
        }
        Object brandId = params.get("brandId");
        if (!ObjectUtils.isEmpty(brandId)) {
            queryWrapper.eq("brand_id", brandId);
        }
        Object min = params.get("min");
        if (!ObjectUtils.isEmpty(min)) {
            queryWrapper.ge("price", min);
        }
        Object max = params.get("max");
        if (!ObjectUtils.isEmpty(max)) {
            queryWrapper.le("price", max);
        }

        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public SkuItemVo item(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVo skuItemVo = new SkuItemVo();
        CompletableFuture<SkuInfo> skuInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
            SkuInfoEntity skuInfoEntity = this.getById(skuId);
            if (!ObjectUtils.isEmpty(skuInfoEntity)) {
                SkuInfo skuInfo = new SkuInfo();
                skuInfo.setSkuId(skuInfoEntity.getSkuId())
                        .setSpuId(skuInfoEntity.getSpuId())
                        .setSkuName(skuInfoEntity.getSkuName())
                        .setSkuDesc(skuInfoEntity.getSkuDesc())
                        .setCatalogId(skuInfoEntity.getCatalogId())
                        .setBrandId(skuInfoEntity.getBrandId())
                        .setSkuDefaultImg(skuInfoEntity.getSkuDefaultImg())
                        .setSkuTitle(skuInfoEntity.getSkuTitle())
                        .setSkuSubtitle(skuInfoEntity.getSkuSubtitle())
                        .setPrice(skuInfoEntity.getPrice())
                        .setSaleCount(skuInfoEntity.getSaleCount());
                Set<Long> skuIdSet = wareFeignService.getSkuHasStock(List.of(skuInfo.getSkuId()));
                if (ObjectUtils.isEmpty(skuIdSet) || skuIdSet.contains(skuInfo.getSkuId())) {
                    skuInfo.setHasStock(true);
                }
                skuItemVo.setSkuInfo(skuInfo);

                return skuInfo;
            }

            return null;
        }, executor);
        CompletableFuture<Void> spuInfoDescFuture = skuInfoCompletableFuture.thenAcceptAsync((res) -> {
            Long spuId = res.getSpuId();
            SpuInfoDescEntity spuInfoDescEntity = spuInfoDescService.getById(spuId);
            if (!ObjectUtils.isEmpty(spuInfoDescEntity)) {
                SpuInfoDesc spuInfoDesc = new SpuInfoDesc();
                spuInfoDesc.setSpuId(spuInfoDescEntity.getSpuId())
                        .setDecript(spuInfoDescEntity.getDecript());
                skuItemVo.setSpuInfoDesc(spuInfoDesc);
            }
        }, executor);
        CompletableFuture<Void> spuItemAttrGroupsFuture = skuInfoCompletableFuture.thenAcceptAsync((res) -> {
            Long spuId = res.getSpuId();
            Long catalogId = res.getCatalogId();
            List<SpuItemAttrGroup> spuItemAttrGroups = attrGroupService.listAttrGroupWithAttrsBySpuIdAndCatalogId(spuId, catalogId);
            if (!ObjectUtils.isEmpty(spuItemAttrGroups)) {
                skuItemVo.setSpuItemAttrGroups(spuItemAttrGroups);
            }
        }, executor);
        CompletableFuture<Void> skuSaleAttrsFuture = skuInfoCompletableFuture.thenAcceptAsync((res) -> {
            Long spuId = res.getSpuId();
            List<SkuSaleAttr> skuSaleAttrs = skuSaleAttrValueService.listSkuSaleAttrBySpuId(spuId);
            if (!ObjectUtils.isEmpty(skuSaleAttrs)) {
                skuItemVo.setSkuSaleAttrs(skuSaleAttrs);
            }
        }, executor);
        CompletableFuture<Void> skuImagesFuture = CompletableFuture.runAsync(() -> {
            List<SkuImagesEntity> skuImagesEntities = skuImagesService.list(new QueryWrapper<SkuImagesEntity>().eq("sku_id", skuId));
            if (!ObjectUtils.isEmpty(skuImagesEntities)) {
                List<SkuImage> skuImages = skuImagesEntities.stream().map(skuImagesEntity -> {
                    SkuImage skuImage = new SkuImage();
                    skuImage.setSkuId(skuImagesEntity.getSkuId())
                            .setSkuId(skuImagesEntity.getSkuId())
                            .setImgUrl(skuImagesEntity.getImgUrl())
                            .setImgSort(skuImagesEntity.getImgSort())
                            .setDefaultImg(skuImagesEntity.getDefaultImg());
                    return skuImage;
                }).collect(Collectors.toList());
                skuItemVo.setSkuImages(skuImages);
            }
        }, executor);
        CompletableFuture<Void> seckillSkuRedisFuture = CompletableFuture.runAsync(() -> {
            SeckillSkuRedisVo seckillSkuRedisVo = seckillFeignService.getSeckillInfoBySkuId(skuId);
            skuItemVo.setSeckillSkuRedisVo(seckillSkuRedisVo);
        }, executor);
        CompletableFuture.allOf(skuInfoCompletableFuture,
                spuInfoDescFuture,
                spuItemAttrGroupsFuture,
                skuSaleAttrsFuture,
                skuImagesFuture,
                seckillSkuRedisFuture).get();
        return skuItemVo;
    }

    @Override
    public BigDecimal getPriceBySkuId(Long skuId) {
        SkuInfoEntity skuInfoEntity = baseMapper.selectOne(new QueryWrapper<SkuInfoEntity>().eq("sku_id", skuId).select("price"));
        if (!ObjectUtils.isEmpty(skuInfoEntity)) {
            BigDecimal price = skuInfoEntity.getPrice();
            log.debug("getPriceBySkuId -> {}", price);
            return price;
        }
        return null;
    }

}